#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char* argv[])
{
    int pid = 0;
    int i = 0;

    if( (pid = fork()) > 0 ) { // 1. 第一次fork，创建子进程
        printf("parrent = %d, ppid = %d, pgid = %d, sid = %d\n", 
                    getpid(), getppid(), getpgrp(), getsid(getpid()));
        printf("child: %d\n", pid);
        exit(0); // 父进程退出，子进程成为后台进程
    } else if( pid == 0 ) {
        setsid(); // 2. 子进程创建新会话。脱离终端，成为新会话首进程

        if ((pid = fork()) > 0) { // 3. 第二次fork，创建孙进程
            printf("child = %d, ppid = %d, pgid = %d, sid = %d\n", 
                        getpid(), getppid(), getpgrp(), getsid(getpid()));
            printf("groundson: %d\n", pid);
            exit(0); // 子进程退出，确保孙进程不是会话首进程，防止重新打开控制终端
        }
        
        if(pid == 0) { //4. 孙进程，真正的守护进程
            // 设置文件权限掩码为 0，避免继承 umask 限制
            umask(0);
            chdir("/");
            
            // 5. 关闭标准输入/输出/错误
            close(STDIN_FILENO);
            close(STDOUT_FILENO);
            close(STDERR_FILENO);
            
            // 6. 重定向标准输入输出和标准错误输出到 /dev/null
            i += open("/dev/null", O_RDONLY); // 0 -- STD_IN
            i += open("/home/code_folder/linux_system_program/10守护进程深度分析/01守护进程/test.log", O_WRONLY); // 1 -- STD_OUT
            i += open("/dev/null", O_RDWR); // 2 -- STD_ERR

            // 注意：此时 printf 无效，因为输出已指向 /dev/null
            printf("child = %d, ppid = %d, pgid = %d, sid = %d\n", 
                        getpid(), getppid(), getpgrp(), getsid(getpid()));
            printf("i = %d\n", i);

            while (1) {
                // do something
                printf("i = %d\n", i++);
                sleep(1);
                fflush(stdout);
            }
        }
    } else {
        printf("fork error...\n");
    }  
    
    sleep(240);
    
    return 0;
}
